package com.tool.engine.config;

import com.tool.engine.export.capacity.CapacityLimit;
import com.tool.engine.export.capacity.ExportTaskCapacityLimit;
import com.tool.engine.export.engine.DefaultExportTaskEngine;
import com.tool.engine.export.engine.ExportTaskEngine;
import com.tool.engine.export.factory.thread.ExportTaskThreadPoolFactory;
import com.tool.engine.export.mertics.Collector;
import com.tool.engine.export.mertics.MetricsCollector;
import com.tool.engine.export.mertics.collect.Collect;
import com.tool.engine.export.mertics.collect.ExportCollect;
import com.tool.engine.export.policy.AdjusterPolicy;
import com.tool.engine.export.policy.DynamicThresholdAdjuster;
import com.tool.engine.export.processor.CommonExportTaskProcessor;
import com.tool.engine.export.processor.ExportTaskProcessor;
import com.tool.engine.export.task.TaskDecorator;
import com.tool.engine.export.write.allocator.DataWriteAllocator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
@ConditionalOnProperty(prefix = "export",name = "enabled", havingValue = "true",matchIfMissing = true)
public class ExportTaskAutoConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "export.task.common")
    public ExportTaskProperties exportTaskProperties() {
        return new ExportTaskProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "export.task.policy")
    public AdjusterProperties adjusterProperties() {
        return new AdjusterProperties();
    }

    @Bean
    @ConditionalOnMissingBean(CapacityLimit.class)
    public CapacityLimit exportTaskCapacityLimit(ExportTaskProperties exportTaskProperties) {
        ExportTaskCapacityLimit exportTaskCapacityLimit = new ExportTaskCapacityLimit();
        exportTaskCapacityLimit.setFactor(exportTaskProperties.getFactor());
        return exportTaskCapacityLimit;
    }

    @Bean
    @ConditionalOnMissingBean(Collect.class)
    public Collect collect() {
        return new ExportCollect();
    }

    @Bean
    @ConditionalOnMissingBean(Collector.class)
    public Collector metricsCollector( Collect collect) {
        MetricsCollector metricsCollector = new MetricsCollector();
        metricsCollector.setCollect(collect);
        return metricsCollector;
    }

    @Bean
    @ConditionalOnMissingBean(AdjusterPolicy.class)
    public AdjusterPolicy adjusterPolicy( Collector collector, AdjusterProperties adjusterProperties) {
        return new DynamicThresholdAdjuster(adjusterProperties, collector);
    }

    @Bean
    @ConditionalOnMissingBean(DataWriteAllocator.class)
    public DataWriteAllocator dataWriteAllocator(ExportTaskProperties exportTaskProperties, Collector collector) {
        DataWriteAllocator dataWriteAllocator = new DataWriteAllocator();
        dataWriteAllocator.setWriteCount(exportTaskProperties.getWriteCount());
        dataWriteAllocator.setCollector(collector);
        return dataWriteAllocator;
    }

    @Bean("common")
    public ExportTaskProcessor exportTaskEngineProcessor(CapacityLimit exportTaskCapacityLimit, DataWriteAllocator dataWriteAllocator, AdjusterPolicy adjusterPolicy, Collector collector) {
        CommonExportTaskProcessor commonExportTaskProcessor = new CommonExportTaskProcessor();
        commonExportTaskProcessor.setAdjusterPolicy(adjusterPolicy);
        commonExportTaskProcessor.setExportTaskCapacityLimit(exportTaskCapacityLimit);
        commonExportTaskProcessor.setDataWriteAllocator(dataWriteAllocator);
        commonExportTaskProcessor.setCollector(collector);
        return commonExportTaskProcessor;
    }

    @Bean
    @ConditionalOnMissingBean(TaskDecorator.class)
    @ConditionalOnMissingClass("brave.Tracing")
    public TaskDecorator defaultTaskDecorator() {
        return new NoOpTraceContextDecorator();
    }

    @Bean
    @ConditionalOnMissingBean(ExportTaskEngine.class)
    public ExportTaskEngine defaultExportTaskEngine(ExportTaskProperties exportTaskProperties, Collector collector, TaskDecorator taskDecorator) {
        DefaultExportTaskEngine defaultExportTaskEngine = new DefaultExportTaskEngine();
        defaultExportTaskEngine.setFilePath(exportTaskProperties.getFilePath());
        defaultExportTaskEngine.setCollector(collector);
        defaultExportTaskEngine.setTaskDecorator(taskDecorator);
        defaultExportTaskEngine.setThreadPoolExecutor(ExportTaskThreadPoolFactory.createExecutorService(exportTaskProperties));
        return  defaultExportTaskEngine;
    }


    public static class NoOpTraceContextDecorator implements TaskDecorator {
        @Override
        public Runnable decorate(Runnable runnable) {
            return runnable;
        }
    }
}

